const std = @import("std");

// 尽管这个函数看起来是命令式的，
// 但请注意它的工作是声明式地构建一个由外部运行器执行的构建图。
pub fn build(b: *std.Build) void {
    // 标准目标选项允许运行 `zig build` 的人选择要构建的目标
    // 。在这里我们没有覆盖默认值，这意味着允许任何目标，
    // 默认是本地(native)。还有其他选项可以限制支持的目标集。
    const target = b.standardTargetOptions(.{});

    // 标准优化选项允许运行 `zig build` 的人选择 Debug、ReleaseSafe、
    // ReleaseFast 和 ReleaseSmall 之间的优化模式
    // 。在这里我们没有设置首选的发布模式，允许用户自行决定如何优化。
    const optimize = b.standardOptimizeOption(.{});

    // 这会创建一个“模块”，它代表一组源文件以及一些编译选项，
    // 比如优化模式和链接的系统库。
    // 我们编译的每个可执行文件或库都将基于一个或多个模块。
    const lib_mod = b.createModule(.{
        // `root_source_file` 是该模块的 Zig “入口点”。
        // 如果一个模块只包含例如外部目标文件，你可以将其设为 `null`。
        // 在这种情况下，主源文件只是一个路径，但在更复杂的构建脚本中，这可能是一个生成的文件。
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    // 我们还将为另一个入口点 'main.zig' 创建一个模块。
    const exe_mod = b.createModule(.{
        // `root_source_file` 是该模块的 Zig “入口点”。如果一个模块只包含例如外部目标文件，你可以将其设为 `null`。在这种情况下，主源文件只是一个路径，但在更复杂的构建脚本中，这可能是一个生成的文件。
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // 模块之间可以通过 `std.Build.Module.addImport` 函数相互依赖。
    // 这允许 Zig 源代码使用 `@import("foo")`，其中 'foo' 不是文件路径。在这里，我们设置 `exe_mod` 导入 `lib_mod`。
    exe_mod.addImport("hello_lib", lib_mod);
    // exe_mod.addImport("hello_dir_lib", hello_lib_mod);
    const rbtree_dep = b.dependency("rbtree", .{
        .target = target,
        .optimize = optimize,
    });

    exe_mod.addImport("rbtree", rbtree_dep.module("rbtree"));
    // 现在，我们将基于上面创建的模块创建一个静态库。
    // 这会创建一个 `std.Build.Step.Compile`，它是实际调用编译器的构建步骤。
    const lib = b.addLibrary(.{
        .linkage = .static,
        .name = "hello",
        .root_module = lib_mod,
    });

    // 这声明了当用户执行 "install" 步骤（运行 `zig build` 时的默认步骤）时，
    // 库将被安装到标准位置。
    b.installArtifact(lib);
    // b.addInstallDirectory
    // 这会创建另一个 `std.Build.Step.Compile`，但这个是构建可执行文件，而不是静态库。
    const exe = b.addExecutable(.{
        .name = "hello",
        .root_module = exe_mod,
    });
    // exe.linkSystemLibrary("m");
    // 下面连接libc库
    exe.linkLibC();
    // if (target.result.os.tag == .windows)
    //        // 连接到系统的 ole32
    //        exe.linkSystemLibrary("ole32")
    //    else
    //        // 链接到系统的 libz
    //        exe.linkSystemLibrary("z");

    // exe.linkLibrary(lib);
    // exe.linkLibCpp();
    // exe.addModule("rbtree", rbtree_dep.module("rbtree"));
    // b.addInstallDirectory
    // 这声明了当用户执行 "install" 步骤（运行 `zig build` 时的默认步骤）时，可执行文件将被安装到标准位置。
    b.installArtifact(exe);
    // addCSourceFile
    // 这在构建图中*创建*一个 Run 步骤，当另一个依赖于它的步骤被执行时会被执行。下面的下一行将建立这样的依赖关系。
    const run_cmd = b.addRunArtifact(exe);

    // 通过让 run 步骤依赖于 install 步骤，它将从安装目录运行，
    // 而不是直接从缓存目录运行。这不是必须的，
    // 但如果应用程序依赖于其他已安装的文件，
    // 这可以确保它们存在并且在预期的位置。
    // 就是因为这个依赖项，所以运行zig build run会生成静态库。
    run_cmd.step.dependOn(b.getInstallStep());

    // 这允许用户在构建命令本身中向应用程序传递参数，例如：`zig build run -- arg1 arg2 etc`
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // 这会创建一个构建步骤。它将在 `zig build --help` 菜单中可见，并且可以像这样选择：`zig build run`。这将执行 `run` 步骤，而不是默认的 "install"。
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
    const test_step = b.step("test", "Run unit tests");

    const test_dir = [_][]const u8{"src"};
    for (test_dir, 0..) |subdir, i| {
        // const dir: ?[]u8 = b.build_root.join(b.allocator, &.{subdir}) catch null;
        var dir: ?[]u8 = b.build_root.join(b.allocator, &.{subdir}) catch |err| blk: {
            std.debug.print("join failed: {}\n", .{err});
            break :blk null;
        };

        if (dir) |rdir| {
            defer {
                b.allocator.free(rdir);
                dir = null;
            }

            var open_dir = std.fs.openDirAbsolute(rdir, .{ .iterate = true }) catch continue;

            defer open_dir.close();

            var walker = open_dir.walk(b.allocator) catch continue;
            defer walker.deinit();
            // const walt = walker.next();
            // if (walt) |trn| {
            //     std.debug.print("walk failed: {}\n", .{trn});
            // }
            // if (walker.next()) |_| {
            //     // const aa = 1;
            //     // const aa_p = &aa;
            //     // aa_p *= 3;
            //     std.debug.print("nihao \n", .{});
            //     // std.debug.print("walk chegog \n");
            // } else |_| {
            //     // std.debug.print("walk failed:{}\n", .{@TypeOf(err)});
            // }
            // std.debug.print("begin walk \n", .{});
            while (walker.next() catch null) |entry| {
                // std.debug.print("entry type:{}\n", .{@TypeOf(entry)});
                // var testuu: [:0]const u8 = "fdsfsd";
                // testuu = entry.path;
                // std.debug.print("full path**:{s}\n", .{entry.path});

                // full_path这里其实是个相对路径，如果是绝对路径会报错
                const full_path = b.pathJoin(&.{ subdir, entry.path });
                defer b.allocator.free(full_path);
                // const full_path = b.pathJoin(&.{ rdir, entry.path });//这里绝对路径--报错

                // std.debug.print("full path1:{s}\n", .{full_path});

                if (!std.mem.endsWith(u8, full_path, ".zig")) continue;
                // std.debug.print("full path:{s}\n", .{full_path});

                const one_test = b.addTest(.{
                    .root_source_file = b.path(full_path),
                    .target = target,
                    .optimize = optimize,
                });
                // one_test.root_module.addImport("hello_lib", lib_mod);

                // // const one_run_test = b.addRunArtifact(some_test);
                const one_run_test = b.addRunArtifact(one_test);
                test_step.dependOn(&one_run_test.step);
            }
            // else |_| {}
        }

        // if (dir == null) {
        //     continue;
        // }
        // defer b.allocator.free(dir.?);

        // const open_dir = std.fs.openDirAbsolute(dir, .{ .iterate = true });
        // defer b.allocator.free(dir);
        // defer dir.deinit();

        std.debug.print("type of sub dir {}\n", .{@TypeOf(dir)});

        std.debug.print("{s} {}\n", .{ subdir, i });
    }
    // 创建一个用于单元测试的步骤。它只构建测试可执行文件，但不会运行它。
    const lib_unit_tests = b.addTest(.{
        .root_module = lib_mod,
    });
    // const lib_unit_tests1 = b.addTest(.{
    //     .root_module = lib_mod,
    // });
    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
    // const run_lib_unit_tests1 = b.addRunArtifact(lib_unit_tests1);

    // addTest既可以指定.root_module,也可以指定.root_source_file
    const exe_unit_tests = b.addTest(.{
        .root_module = exe_mod,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

    // 类似于之前创建 run 步骤，这会向 `zig build --help` 菜单暴露一个 `test` 步骤，为用户提供请求运行单元测试的方法。
    test_step.dependOn(&run_lib_unit_tests.step);
    // test_step.dependOn(&run_lib_unit_tests1.step);
    test_step.dependOn(&run_exe_unit_tests.step);

    // exe.addCSourceFile(.{
    //     .file = b.path("src/main.cc"),
    //     .flags = &.{},
    // });
    // const object = b.addObject(.{
    //     .name = "object",
    //     .root_source_file = b.path("src/root.zig"),
    //     .target = target,
    //     .optimize = optimize,
    // });
    // object.getEmittedDocs(),
    // // 创建一个 step
    // const docs_step = b.step("docs", "Generate docs");

    // // 生成文档
    // const docs_install = b.addInstallDirectory(.{
    //     // 指定文档来源
    //     .source_dir = object.getEmittedDocs(),
    //     // 指定安装目录
    //     .install_dir = .prefix,
    //     // 指定文档子文件夹
    //     .install_subdir = "docs",
    // });

}
